//
//  BleDataTool.swift
//  MMTest
//
//  Created by liujianlong on 2022/9/21.
//

import UIKit
import Foundation
import CoreBluetooth
import TCCKit
public protocol CCBLEData{
    var head:String{get}
    var cmd:String{get}
    var ack:String{get}
    var hex:String{get}
    var data:Data{get}
    var service_uuidString:String{get}
    var write_char_uuidString:String{get}
    var read_char_uuidString:String{get}
    func write(_ peripheral:CBPeripheral?)
    
}

enum BLEData{
    ///开/关机
    case On_off(_ on:Bool)
    /// 设置温度
    case setupTemp(_ temp:Int)
    ///是否开启振动马达
    case motorOn_off(_ on:Bool)
    ///设置振动马达定时
    case motorTime(_ time:Int)
    ///实时数据更新
    case dataupdate
    ///查询设备状态
    case checkStatus
}

extension BLEData{
    var head:String{
        return "55AA"
    }
    var cmd : String{
        switch self{
        case let .On_off(on):
            let data = (on ? "01":"00")
            return "01" + data + checkcode("01", data)
        case let .setupTemp(temp):
            let data = ("\(temp)".toHex().fix(2, "0") as String)
            return "11" + data + checkcode("11", data)
        case let .motorOn_off(on):
            let data = (on ? "01":"00")
            return "12" + data + checkcode("12", data)
        case let .motorTime(time):
            let data = ("\(time)".toHex().fix(2, "0") as String)
            return "13" + data + checkcode("13", data)
        case .checkStatus:
            return "21" + "01" + checkcode("21", "01")
        default:
            return ""
        }
    }
    
    func checkcode(_ smc:String,_ data:String)->String{
        let num1 = smc.toDecimal()
        let num2 = data.toDecimal()
        ///校验方法：1，按位或与(XOR操作)
        let xor = num1 ^ num2
        ///2，取最低位
        let lowestByte = xor & 0xFF
        let str = "\(lowestByte)".toHex().fix(2, "0") as String
        return str
    }
    
    var ack:String{
        switch self{
        case .dataupdate:
            return "AA55" + "20"
        default:
            return "AA55" + self.cmd[0...1]
        }
    }
    
    var data:Data{
        let str = self.head + self.cmd
        return str.hexadecimal() ?? Data()
    }
    
    var service_uuidString:String{
        return "FFF0"
    }
    
    var write_char_uuidString:String{
        return "FFF3"
    }
    var read_char_uuidString:String{
        return "FFF4"
    }
    
    func write(_ peripheral:CBPeripheral?){
        guard let per = peripheral else{return}
        guard let array = per.characteristics[self.service_uuidString] else {return}
        guard let dict = array.filter({$0.keys.first == self.write_char_uuidString}).first else {return}
        guard let char = dict[self.write_char_uuidString] else {return}
        per.writeValue(self.data, for: char, type: .withoutResponse)
    }
}

class BleDataTool{
    ///数据更新
    class func handleData(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?){
        let bytes = [UInt8](characteristic.value ?? Data())
        if bytes.count <= 0{return}
        let ack = bytes[0...2].map{String(format:"%.2X",$0)}.joined()
        let data = bytes[0...bytes.count-1].map{String(format:"%.2X ",$0)}.joined()
        var param = [String:Any]()
        switch ack{
        case BLEData.dataupdate.ack:
            ///解析名称
            let mac_array = peripheral.mac.components(separatedBy: ":")
            let direction = mac_array[0].hasPrefix("7C") ? "L" : "R"
            let lastTwoMac = mac_array[mac_array.count - 2] + mac_array[mac_array.count - 1]
            let name = peripheral.name! + "_" + lastTwoMac + direction
            ///解析电量
            var elect_num = String(format:"%.2x", bytes[3]).toDecimal()
            //            var elect_num = str.toDecimal() < 6000 ? 0 : (str.toDecimal() - 6000) / 24
            elect_num = elect_num > 100 ? 100 : elect_num
            ///解析当前温度
            let current_t = String(format:"%.2x", bytes[5]).toDecimal()
            ///解析设置温度
            let config_t = String(format:"%.2x", bytes[6]).toDecimal()
            param = ["name":name, "elect":elect_num,"current_t":current_t,"config_t":config_t]
            peripheral.model.name = name
            peripheral.model.elect = elect_num
            peripheral.model.current_t = current_t
            peripheral.model.config_t = config_t
            if peripheral.model.ison == false{
                BLEData.checkStatus.write(peripheral)
            }
        case BLEData.checkStatus.ack:
            peripheral.model.ison = String(format:"%.2x", bytes[3]) == "01"
        case BLEData.setupTemp(0).ack:
            if peripheral.model.targetValue == 10000{return}
            peripheral.model.config_t = peripheral.model.targetValue
            //            MyPrint("=====设置回调  data =  \(peripheral.model.didChange) ====== \(String(format:"%.2x", bytes[3]))")
            break
        default:
            break
        }
        MyPrint("=====ack = \(ack) =   data = \(data)")
        NotifyTool.post(ack,param)
    }
}


private var SockModelKey = "SockModelKey"
extension CBPeripheral{
    @objc var model : SockModel{
        set{objc_setAssociatedObject(self, &SockModelKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)}
        get{return objc_getAssociatedObject(self, &SockModelKey) as? SockModel ?? SockModel()}
    }
}
